package com.xzmzhp.utils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * @author 王源(xm)
 * @title: DateUtil
 * @date 2021/10/25 10:14
 * @Description: 时间工具类
 */
public class DateUtil implements Cloneable {

    /**
     * 英文简写（默认）如：2010-12-01
     */
    public static final String FORMAT_SHORT = "yyyy-MM-dd";

    /**
     * 英文全称  如：2010-12-01 23:15:06
     */
    public static final String FORMAT_LONG = "yyyy-MM-dd HH:mm:ss";

    /**
     * 精确到毫秒的完整时间    如：yyyy-MM-dd HH:mm:ss.S
     */
    public static final String FORMAT_FULL = "yyyy-MM-dd HH:mm:ss.S";

    /**
     * 中文简写  如：2010年12月01日
     */
    public static final String FORMAT_SHORT_CN = "yyyy年MM月dd";

    /**
     * 中文全称  如：2010年12月01日  23时15分06秒
     */
    public static final String FORMAT_LONG_CN = "yyyy年MM月dd日  HH时mm分ss秒";

    /**
     * 精确到毫秒的完整中文时间
     */
    public static final String FORMAT_FULL_CN = "yyyy年MM月dd日  HH时mm分ss秒SSS毫秒";

    /**
     * 时间
     */
    private Date date = null;

    /**
     * 时间工厂
     */
    private SimpleDateFormat format = null;

    /**
     * 无参构造
     */
    DateUtil() {
    }

    /**
     * 有参构造
     *
     * @param source 对象本身
     */
    DateUtil(DateUtil source) {
        if (source != null) {
            this.date = source.date;
            this.format = source.format;
        } else {
            this.date = null;
            this.format = null;
        }
    }


    /**
     * 获取当前时间
     *
     * @return 时间
     */
    public static DateUtil now() {
        DateUtil dateUtil = new DateUtil();
        dateUtil.setDateTimeWithCurrentTime();
        return dateUtil;
    }

    /**
     * 初始化时间
     */
    void setDateTimeWithCurrentTime() {
        if (this.date == null) {
            this.date = new Date(System.currentTimeMillis());
        } else {
            this.date.setTime(System.currentTimeMillis());
        }
    }

    /**
     * 返回固定格式的字符串
     *
     * @return 时间
     */
    @Override
    public String toString() {
        return toString(FORMAT_LONG);
    }

    /**
     * 时间格式转换为指定格式的字符串
     *
     * @param timeFormat 时间格式
     * @return 时间
     */
    public String toString(String timeFormat) {
        if (this.date == null) {
            return "";
        }
        try {
            return getDateTimeAsString(timeFormat);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 初始化时间格式
     *
     * @param timeFormat 时间格式
     */
    public void setDateTimeFormat(String timeFormat) {
        if (this.format == null) {
            this.format = new SimpleDateFormat(timeFormat);
        } else {
            this.format.applyPattern(timeFormat);
        }
    }

    /**
     * 获取指定格式的时间字符串
     *
     * @param timeFormat 时间格式
     * @return 时间
     */
    public String getDateTimeAsString(String timeFormat) {
        if (this.date == null) {
            return null;
        }
        setDateTimeFormat(timeFormat);
        return this.format.format(this.date);
    }

    /**
     * 将时间字符串格式化为指定格式
     *
     * @param value      时间字符串
     * @param timeFormat 时间格式
     * @return 时间
     */
    public static String getFormatTimeAsString(String value, String timeFormat) {
        try {
            return new SimpleDateFormat(timeFormat).format(new SimpleDateFormat(FORMAT_SHORT).parse(value));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将字符串转换为时间
     *
     * @param value 时间字符串
     * @return 时间
     */
    public static Date getDateTime(String value) {
        try {
            return new SimpleDateFormat(FORMAT_LONG).parse(value);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将时间字符串转换为指定格式的时间类型
     *
     * @param format 时间格式
     * @param value  字符串类型时间
     * @return 时间
     */
    public static Date getDateTime(String format, String value) {
        try {
            return new SimpleDateFormat(format).parse(value);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将时间转为指定格式的字符串
     *
     * @param format 时间格式
     * @param value  时间
     * @return 时间
     */
    public static String getDateTimeToString(String format, Date value) {
        try {
            return new SimpleDateFormat(format).format(value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 设置指定格式的时间
     *
     * @param value      指定时间
     * @param timeFormat 时间格式
     * @return 时间
     * @throws ParseException
     */
    public boolean setDateTimeWithString(String value, String timeFormat) throws ParseException {
        SimpleDateFormat dtFormat = new SimpleDateFormat(timeFormat);
        date = dtFormat.parse(value);
        return true;
    }

    /**
     * 获取时间值（毫秒数）
     *
     * @return 时间
     */
    public long getTimeInMillis() {
        return (date == null ? 0 : date.getTime());
    }

    /**
     * 获取上月的开始时间
     *
     * @return 时间 上月的开始时间
     */
    public static Date getBeginDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取上月的结束时间
     *
     * @return 时间 上月的结束时间
     */
    public static Date getEndDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 2, day);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取本月的开始时间
     *
     * @return 时间 本月的开始时间
     */
    public static Date getBeginDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取本月的结束时间
     *
     * @return 时间 本月的结束时间
     */
    public static Date getEndDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 1, day);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取今年年份
     *
     * @return 时间 今年年份
     */
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return Integer.valueOf(gc.get(1));
    }

    /**
     * 获取本月月份
     *
     * @return 时间 本月月份
     */
    public static int getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(2) + 1;
    }

    /**
     * 获取届信息
     * 本年小于9月份返回上一年信息，大于9月返回本年信息
     * @return 届信息
     */
    public static int getSession(){
        int nowYear = Integer.parseInt(String.valueOf(DateUtil.getNowYear()).substring(2));
        if(DateUtil.getNowMonth()<9){
            return nowYear-1;
        }
        return nowYear;
    }

    /**
     * 获取某个日期的开始时间
     *
     * @return 时间 日期开始时间
     */
    public static Timestamp getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取某个日期的结束时间
     *
     * @return 时间 日期结束时间
     */
    public static Timestamp getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取当前时间加或减几天
     *
     * @return 时间 时间日期
     */
    public static Date getCalcDateByDay(int day) {
        return changeDate(getNowDate(), Calendar.DAY_OF_MONTH, day);
    }

    /**
     * 时间加减指定的数量
     *
     * @param date         时间
     * @param calendarType 日历字段
     * @param count        数量
     * @return 时间
     */
    public static Date changeDate(Date date, int calendarType, int count) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        switch (calendarType) {
            case Calendar.YEAR:
                calendar.add(Calendar.YEAR, count);
                break;
            case Calendar.MONTH:
                calendar.add(Calendar.MONTH, count);
                break;
            case Calendar.DAY_OF_MONTH:
                calendar.add(Calendar.DAY_OF_MONTH, count);
                break;
            case Calendar.HOUR_OF_DAY:
                calendar.add(Calendar.HOUR_OF_DAY, count);
                break;
            case Calendar.MINUTE:
                calendar.add(Calendar.MINUTE, count);
                break;
            case Calendar.SECOND:
                calendar.add(Calendar.SECOND, count);
                break;
            default:
                break;
        }
        return calendar.getTime();
    }

    /**
     * 返回当前时间
     *
     * @return 时间
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 克隆方法
     * 注意克隆对象不要为浅克隆
     *
     * @return DateUtil对象
     * @throws CloneNotSupportedException 克隆异常
     */
    @Override
    protected DateUtil clone() throws CloneNotSupportedException {
        DateUtil dateUtil = (DateUtil) super.clone();
        dateUtil.format = null;
        dateUtil.date = null;
        return dateUtil;
    }
}
